#include "MGUI_EditBox.h"
#include "MGUI_Engine.h"
#include "MGUI_Helper.h"

namespace Myway {

	ImplementRTTI(MGUI_EditBox, MGUI_Widget);

	MGUI_EditBox::MGUI_EditBox(const MGUI_LookFeel * _lookfeel, MGUI_Widget * _parent)
		: MGUI_Widget(_lookfeel, _parent)
	{
		mSelectBackColor = MGUI_Color(0.4f, 0.4f, 0.75f);
		mCursorColor = MGUI_Color(1, 1, 1);

		mSelectIndex = mSelectStartIndex = mSelectIndex = 0;

		mKeyFocused = false;
		mStatic = false;

		mTimerId = -1;
		mSelectVisible = false;

		mTextBox = new MGUI_TextBox(this);
		mTextBox->SetAlign(MGUI_Align::Left | MGUI_Align::VCenter);
	}

	MGUI_EditBox::~MGUI_EditBox()
	{
	}

	void MGUI_EditBox::SetCaption(const MGUI_String & caption)
	{
		mTextBox->SetCaption(caption);
	}

	const MGUI_String & MGUI_EditBox::GetCaption()
	{
		return mTextBox->GetCaption();
	}

	void MGUI_EditBox::SetFont(MGUI_Font * font)
	{
		mTextBox->SetFont(font);
	}

	MGUI_Font * MGUI_EditBox::GetFont()
	{
		return mTextBox->GetFont();
	}

	void MGUI_EditBox::SetTextColor(const MGUI_Color & color)
	{
		mTextBox->SetColor(color);
	}

	const MGUI_Color & MGUI_EditBox::GetTextColor()
	{
		return mTextBox->GetColor();
	}

	void MGUI_EditBox::SetStatic(bool _static)
	{
		mStatic = _static;

		if (MGUI_InputManager::Instance()->GetKeyFocusedWidget() == this)
			MGUI_InputManager::Instance()->SetKeyFocusedWidget(NULL);
	}

	void MGUI_EditBox::OnMousePressed(int _x, int _y, MGUI_MouseButton _id)
	{
		if (mStatic || GetFont() == NULL)
			return ;

		mSelectStartIndex = mSelectEndIndex = 0;

		const MGUI_String & caption = GetCaption();

		const wchar_t * wstr = caption.c_str();
		int length = wcslen(wstr);

		int selectIndex = length;

		const MGUI_Rect & tbRect = mTextBox->GetAbsRect();

		MGUI_RectF myRect;
		myRect.x0 = (float)tbRect.x0;
		myRect.y0 = (float)tbRect.y0;
		myRect.x1 = (float)tbRect.x0;
		myRect.y1 = (float)tbRect.y1;

		for (int i = 0; i < mTextBox->GetGlyphCount(); ++i)
		{
			const MGUI_Glyph * glyph = mTextBox->GetGlyph(i);

			myRect.x1 = myRect.x0 + glyph->advance;

			if (_x < myRect.x1 - 2)
			{
				selectIndex = i;
				break;
			}

			myRect.x0 = myRect.x1;
		}

		mSelectIndex = mSelectStartIndex = mSelectEndIndex = Math::Maximum(selectIndex, 0);
	}

	void MGUI_EditBox::OnMouseDrag(int _x, int _y)
	{
		if (mStatic)
			return ;

		const MGUI_String & caption = GetCaption();

		const wchar_t * wstr = caption.c_str();
		int length = wcslen(wstr);

		int selectIndex = length;

		const MGUI_Rect & tbRect = mTextBox->GetAbsRect();

		MGUI_RectF myRect;
		myRect.x0 = (float)tbRect.x0;
		myRect.y0 = (float)tbRect.y0;
		myRect.x1 = (float)tbRect.x0;
		myRect.y1 = (float)tbRect.y1;

		for (int i = 0; i < mTextBox->GetGlyphCount(); ++i)
		{
			const MGUI_Glyph * glyph = mTextBox->GetGlyph(i);

			myRect.x1 = myRect.x0 + glyph->advance;

			if (_x < myRect.x1 - 2)
			{
				selectIndex = i;
				break;
			}

			myRect.x0 = myRect.x1;
		}

		mSelectStartIndex = Math::Minimum(mSelectIndex, selectIndex);
		mSelectEndIndex = Math::Maximum(mSelectIndex, selectIndex);
	}

	void MGUI_EditBox::OnKeyLostFocus(MGUI_Widget * _new)
	{
		mKeyFocused = false;

		if (mTimerId != -1)
		{
			MGUI_InputManager::Instance()->EndTimer(mTimerId);
			mTimerId = -1;
			mSelectVisible = false;

			MGUI_InputManager::Instance()->eventTimer -= OnTimer(this, &MGUI_EditBox::OnTimer_);
		}
	}

	void MGUI_EditBox::OnKeySetFocus(MGUI_Widget* _old)
	{
		mKeyFocused = true;

		if (!mEnable || mStatic)
			mKeyFocused = false;

		if (mKeyFocused)
		{
			mTimerId = MGUI_InputManager::Instance()->StartTimer(0.5f);
			mSelectVisible = true;

			MGUI_InputManager::Instance()->eventTimer += OnTimer(this, &MGUI_EditBox::OnTimer_);
		}
	}

	void MGUI_EditBox::OnKeyPressed(MGUI_KeyCode _key, MGUI_Char _char)
	{
		if (!mEnable || mStatic)
			return ;

		MGUI_String caption = mTextBox->GetCaption();

		if (_key == MGUI_KeyCode::Escape)
		{
			MGUI_InputManager::Instance()->SetKeyFocusedWidget(NULL);
		}
		
		else if (_key == MGUI_KeyCode::Backspace)
		{
			if (mSelectEndIndex == 0)
				return ;

			if (mSelectEndIndex > mSelectStartIndex)
			{
				caption.Remove(mSelectStartIndex, mSelectEndIndex - mSelectStartIndex);

				mSelectIndex = mSelectStartIndex;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;

				eventTextChanged(caption);

				mTextBox->SetCaption(caption);
			}
			else
			{
				caption.Remove(mSelectIndex - 1, 1);
				mSelectIndex = mSelectIndex - 1;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;

				eventTextChanged(caption);

				mTextBox->SetCaption(caption);
			}
		}

		else if (_key == MGUI_KeyCode::ArrowLeft)
		{
			if (mSelectEndIndex == 0)
				return ;

			if (mSelectEndIndex > mSelectStartIndex)
			{
				mSelectIndex = mSelectStartIndex;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;
			}
			else
			{
				mSelectIndex = mSelectIndex - 1;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;
			}
		}

		else if (_key == MGUI_KeyCode::ArrowRight)
		{
			if (mSelectEndIndex == caption.Length())
				return ;

			if (mSelectEndIndex > mSelectStartIndex)
			{
				mSelectIndex = mSelectEndIndex;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;
			}
			else
			{
				mSelectIndex = Math::Minimum(mSelectIndex + 1, caption.Length());
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;
			}
		}

		else if (_key == MGUI_KeyCode::NumpadEnter ||
			     _key == MGUI_KeyCode::Return)
		{
			eventTextReturn();
			MGUI_InputManager::Instance()->SetKeyFocusedWidget(NULL);
		}

		else if (_char != 0)
		{
			if (MGUI_InputManager::Instance()->GetKeyState(MGUI_KeyCode::LeftControl))
			{
				if (_key == MGUI_KeyCode::C)
				{
					MGUI_String text;

					for (int i = mSelectStartIndex; i < mSelectEndIndex; ++i)
					{
						text += caption[i];
					}

					if (text.Length() > 0)
						MGUI_Clipboard::Instance()->SetText(text);
				}
				else if (_key == MGUI_KeyCode::V)
				{
					MGUI_String text = MGUI_Clipboard::Instance()->GetText();

					if (text.Length() > 0)
					{
						if (mSelectEndIndex > mSelectStartIndex)
						{
							caption.Remove(mSelectStartIndex, mSelectEndIndex - mSelectStartIndex);

							mSelectIndex = mSelectStartIndex;
							mSelectStartIndex = mSelectEndIndex = mSelectIndex;
						}

						caption.Insert(mSelectIndex, text.c_str());

						mSelectIndex += text.Length();
						mSelectStartIndex = mSelectEndIndex = mSelectIndex;

						mTextBox->SetCaption(caption);

						eventTextChanged(caption);
					}
				}
				else if (_key == MGUI_KeyCode::X)
				{
					MGUI_String text;

					for (int i = mSelectStartIndex; i < mSelectEndIndex; ++i)
					{
						text += caption[i];
					}

					if (mSelectEndIndex > mSelectStartIndex)
					{
						caption.Remove(mSelectStartIndex, mSelectEndIndex - mSelectStartIndex);

						mSelectIndex = mSelectStartIndex;
						mSelectStartIndex = mSelectEndIndex = mSelectIndex;

						mTextBox->SetCaption(caption);

						eventTextChanged(caption);
					}

					if (text.Length() > 0)
						MGUI_Clipboard::Instance()->SetText(text);
				}
			}
			else
			{
				if (mSelectEndIndex > mSelectStartIndex)
				{
					caption.Remove(mSelectStartIndex, mSelectEndIndex - mSelectStartIndex);

					mSelectIndex = mSelectStartIndex;
					mSelectStartIndex = mSelectEndIndex = mSelectIndex;
				}

				caption.Insert(mSelectIndex, _char);
				
				mSelectIndex += 1;
				mSelectStartIndex = mSelectEndIndex = mSelectIndex;

				mTextBox->SetCaption(caption);

				eventTextChanged(caption);
			}
		}
	}

	void MGUI_EditBox::OnTimer_(int _id)
	{
		if (_id == mTimerId)
		{
			mSelectVisible = !mSelectVisible;
		}
	}

	void MGUI_EditBox::UpdateRenderItem(MGUI_Layout * _layout)
	{
		if (!mVisible)
			return ;

		const MGUI_LookFeel * _lookfeel = mLookFeel;

		MGUI_Rect clipRect = GetParentClipRect();

		if (_lookfeel)
		{
			MGUI_RenderItem * ri = _layout->GetRenderItem(GetAbsOrder(), _lookfeel->GetSkin());

			const MGUI_Rect & myRect = this->GetAbsRect();
			const MGUI_Rect & clRect = this->GetClientRect();
			const MGUI_RectF & uvRect = MGUI_Helper::Instance()->MapUVRect(_lookfeel->GetUVRect(mState), _lookfeel->GetSkin());
			const MGUI_RectF & uvClientRect = MGUI_Helper::Instance()->MapUVRect(_lookfeel->GetUVClientRect(mState), _lookfeel->GetSkin());

			MGUI_Helper::Instance()->AddRenderItem(ri, myRect, clRect, uvRect, uvClientRect, mColor, clipRect);
		}

		if (mSelectEndIndex > mSelectStartIndex && mState == MGUI_WidgetState::Selected)
		{
			MGUI_RectF myRect = MGUI_RectF(float(mTextBox->GetAbsRect().x0), float(mTextBox->GetAbsRect().y0),
				float(mTextBox->GetAbsRect().x1), float(mTextBox->GetAbsRect().y1));

			for (int i = 0; i < mSelectStartIndex; ++i)
				myRect.x0 += mTextBox->GetGlyph(i)->advance;

			myRect.x1 = myRect.x0;
			for (int i = mSelectStartIndex; i < mSelectEndIndex; ++i)
				myRect.x1 += mTextBox->GetGlyph(i)->advance;

			MGUI_RectF uvRect(0, 0, 1, 1);
			MGUI_RenderItem * ri = _layout->GetRenderItem(GetAbsOrder() + MGUI_Order::TextBack, MGUI_Helper::Instance()->GetWhiteTexture());

			MGUI_RectF _rect, _uv;

			if (MGUI_Helper::Instance()->Clip(_rect, _uv, myRect, uvRect, clipRect))
				ri->AddQuad(MGUI_Helper::Instance()->GetQuad(_rect, _uv, mSelectBackColor));
		}

		for (int i = 0; i < mChildren.Size(); ++i)
		{
			mChildren[i]->UpdateRenderItem(_layout);
		}

		if (mSelectStartIndex == mSelectEndIndex && mSelectVisible)
		{
			MGUI_RectF myRect = MGUI_RectF(float(mTextBox->GetAbsRect().x0), float(mTextBox->GetAbsRect().y0),
										   float(mTextBox->GetAbsRect().x1), float(mTextBox->GetAbsRect().y1));

			for (int i = 0; i < mSelectIndex; ++i)
				myRect.x0 += mTextBox->GetGlyph(i)->advance;

			myRect.x1 = myRect.x0 + 1;
			
			MGUI_RectF uvRect;

			uvRect.x0 = 0;
			uvRect.y0 = 0;
			uvRect.x1 = 1;
			uvRect.y1 = 1;

			MGUI_RenderItem * ri = _layout->GetRenderItem(GetAbsOrder() + MGUI_Order::TextCursor, MGUI_Helper::Instance()->GetWhiteTexture());

			MGUI_RectF _rect, _uv;

			if (MGUI_Helper::Instance()->Clip(_rect, _uv, myRect, uvRect, clipRect))
				ri->AddQuad(MGUI_Helper::Instance()->GetQuad(_rect, _uv, mCursorColor));
		}

	}


}